/**
 * n8n 节点数据库服务
 *
 * 使用 Prisma 管理 n8n 节点信息，支持高效的关键词搜索和节点查询
 */

import { PrismaClient } from '@prisma/client';

export interface NodeSearchResult {
  id: number;
  name: string;
  displayName: string;
  description: string | null;
  version: number[];
  group: string[];
  category: string | null;
  subtitle: string | null;
  keywords: string;
  recommendValue: number;
}

export interface NodeSearchOptions {
  /** 搜索关键词 */
  query?: string;
  /** 节点类别过滤 */
  category?: string;
  /** 节点分组过滤 */
  group?: string;
  /** 最小推荐值（>=该值的节点） */
  minRecommendValue?: number;
  /** 限制返回数量 */
  limit?: number;
  /** 跳过数量（分页用） */
  offset?: number;
}

export class N8nNodeDatabaseService {
  private prisma: PrismaClient;

  constructor() {
    this.prisma = new PrismaClient();
  }

  /**
   * 关键词搜索节点
   */
  async searchNodes(options: NodeSearchOptions = {}): Promise<{
    nodes: NodeSearchResult[];
    total: number;
  }> {
    const { query, category, group, minRecommendValue, limit = 20, offset = 0 } = options;

    // 构建搜索条件
    const where: any = {};

    // 关键词搜索（支持全文搜索）
    if (query) {
      where.OR = [
        { name: { contains: query } },
        { displayName: { contains: query } },
        { description: { contains: query } },
        { keywords: { contains: query } },
      ];
    }

    // 类别过滤
    if (category) {
      where.category = category;
    }

    // 分组过滤
    if (group) {
      where.group = { contains: group };
    }

    // 推荐值过滤
    if (minRecommendValue !== undefined) {
      where.recommendValue = { gte: minRecommendValue };
    }

    // 执行搜索
    const [nodes, total] = await Promise.all([
      this.prisma.nodeType.findMany({
        where,
        select: {
          id: true,
          name: true,
          displayName: true,
          description: true,
          version: true,
          group: true,
          category: true,
          subtitle: true,
          keywords: true,
          recommendValue: true,
        },
        orderBy: [
          {
            recommendValue: 'desc', // 推荐值高的优先
          },
          {
            displayName: 'asc', // 相同推荐值时按名称排序
          },
        ],
        take: limit,
        skip: offset,
      }),
      this.prisma.nodeType.count({ where }),
    ]);

    // 解析 group 和 version JSON 字符串为数组
    const processedNodes = nodes.map(node => ({
      ...node,
      group: this.parseJsonArray(node.group),
      version: this.parseVersionArray(node.version),
    }));

    return {
      nodes: processedNodes,
      total,
    };
  }

  /**
   * 根据节点名称获取详细信息
   */
  async getNodeDetails(nodeName: string): Promise<any | null> {
    const node = await this.prisma.nodeType.findUnique({
      where: { name: nodeName },
    });

    if (!node) {
      return null;
    }

    // 解析完整配置 JSON
    try {
      return {
        ...node,
        group: this.parseJsonArray(node.group),
        version: this.parseVersionArray(node.version),
        fullConfig: JSON.parse(node.fullConfig),
      };
    } catch (error) {
      console.error(`解析节点 ${nodeName} 配置失败:`, error);
      return {
        ...node,
        group: this.parseJsonArray(node.group),
        version: this.parseVersionArray(node.version),
        fullConfig: null,
      };
    }
  }

  /**
   * 批量插入或更新节点数据
   */
  async upsertNodes(
    nodes: Array<{
      name: string;
      displayName: string;
      description?: string;
      version?: number | number[];
      group?: string[];
      category?: string;
      subtitle?: string;
      recommendValue?: number;
      fullConfig: any;
    }>
  ): Promise<{ created: number; updated: number }> {
    let created = 0;
    let updated = 0;

    for (const nodeData of nodes) {
      // 生成关键词
      const keywords = this.generateKeywords(nodeData);
      // 计算推荐值
      const recommendValue = nodeData.recommendValue ?? this.calculateRecommendValue(nodeData);

      try {
        await this.prisma.nodeType.upsert({
          where: { name: nodeData.name },
          update: {
            displayName: nodeData.displayName,
            description: nodeData.description || null,
            version: Array.isArray(nodeData.version)
              ? JSON.stringify(nodeData.version)
              : JSON.stringify([nodeData.version || 1]),
            group: JSON.stringify(nodeData.group || []),
            category: nodeData.category || null,
            subtitle: nodeData.subtitle || null,
            recommendValue,
            keywords,
            fullConfig: JSON.stringify(nodeData.fullConfig),
          },
          create: {
            name: nodeData.name,
            displayName: nodeData.displayName,
            description: nodeData.description || null,
            version: Array.isArray(nodeData.version)
              ? JSON.stringify(nodeData.version)
              : JSON.stringify([nodeData.version || 1]),
            group: JSON.stringify(nodeData.group || []),
            category: nodeData.category || null,
            subtitle: nodeData.subtitle || null,
            recommendValue,
            keywords,
            fullConfig: JSON.stringify(nodeData.fullConfig),
          },
        });

        // 这里简化处理，假设都是创建新的
        created++;
      } catch (error) {
        console.error(`处理节点 ${nodeData.name} 失败:`, error);
      }
    }

    return { created, updated };
  }

  /**
   * 获取所有可用的类别
   */
  async getCategories(): Promise<string[]> {
    const result = await this.prisma.nodeType.findMany({
      select: { category: true },
      distinct: ['category'],
      where: { category: { not: null } },
    });

    return result
      .map(r => r.category)
      .filter((cat): cat is string => cat !== null)
      .sort();
  }

  /**
   * 获取数据库统计信息
   */
  async getStats(): Promise<{
    totalNodes: number;
    categories: number;
    lastUpdated: Date | null;
  }> {
    const [totalNodes, categories, lastNode] = await Promise.all([
      this.prisma.nodeType.count(),
      this.getCategories().then(cats => cats.length),
      this.prisma.nodeType.findFirst({
        orderBy: { updatedAt: 'desc' },
        select: { updatedAt: true },
      }),
    ]);

    return {
      totalNodes,
      categories,
      lastUpdated: lastNode?.updatedAt || null,
    };
  }

  /**
   * 清空所有节点数据
   */
  async clearAllNodes(): Promise<number> {
    const result = await this.prisma.nodeType.deleteMany();
    return result.count;
  }

  /**
   * 生成搜索关键词
   */
  private generateKeywords(nodeData: {
    name: string;
    displayName: string;
    description?: string;
    group?: string[];
    category?: string;
    subtitle?: string;
  }): string {
    const keywords: string[] = [];

    // 添加名称相关关键词
    keywords.push(nodeData.name.toLowerCase());
    keywords.push(nodeData.displayName.toLowerCase());

    // 从名称中提取单词（驼峰命名和空格分隔）
    const nameWords = nodeData.name
      .replace(/([A-Z])/g, ' $1')
      .toLowerCase()
      .split(/\s+/)
      .filter(w => w.length > 1);
    keywords.push(...nameWords);

    // 从显示名称中提取单词
    const displayWords = nodeData.displayName
      .toLowerCase()
      .split(/[\s\-_]+/)
      .filter(w => w.length > 1);
    keywords.push(...displayWords);

    // 添加描述中的关键词
    if (nodeData.description) {
      const descWords = nodeData.description
        .toLowerCase()
        .split(/[\s\-_.,;:!?]+/)
        .filter(w => w.length > 2);
      keywords.push(...descWords.slice(0, 10)); // 限制描述关键词数量
    }

    // 添加分组关键词
    if (nodeData.group) {
      keywords.push(...nodeData.group.map(g => g.toLowerCase()));
    }

    // 添加类别关键词
    if (nodeData.category) {
      keywords.push(nodeData.category.toLowerCase());
    }

    // 添加副标题关键词
    if (nodeData.subtitle) {
      const subtitleWords = nodeData.subtitle
        .toLowerCase()
        .split(/[\s\-_]+/)
        .filter(w => w.length > 1);
      keywords.push(...subtitleWords);
    }

    // 去重并返回
    return [...new Set(keywords)].filter(k => k.length > 0).join(' ');
  }

  /**
   * 解析 JSON 数组字符串
   */
  private parseJsonArray(jsonStr: string): string[] {
    try {
      const parsed = JSON.parse(jsonStr);
      return Array.isArray(parsed) ? parsed : [];
    } catch {
      return [];
    }
  }

  /**
   * 解析版本 JSON 数组字符串，转换为数字数组
   */
  private parseVersionArray(jsonStr: string): number[] {
    try {
      const parsed = JSON.parse(jsonStr);
      if (Array.isArray(parsed)) {
        return parsed.map(v => (typeof v === 'number' ? v : parseFloat(v) || 1));
      }
      return [1];
    } catch {
      return [1];
    }
  }

  /**
   * 智能计算节点推荐值（1-10）
   */
  private calculateRecommendValue(nodeData: {
    name: string;
    displayName: string;
    category?: string;
    group?: string[];
    description?: string;
  }): number {
    // 核心节点，最高推荐
    const coreNodes = [
      'n8n-nodes-base.httpRequest',
      'n8n-nodes-base.code',
      'n8n-nodes-base.if',
      'n8n-nodes-base.set',
      'n8n-nodes-base.editFields',
      'n8n-nodes-base.switch',
      'n8n-nodes-base.merge',
      'n8n-nodes-base.function',
      'n8n-nodes-base.functionItem',
      'n8n-nodes-base.executeWorkflow',
      'n8n-nodes-base.start',
      'n8n-nodes-base.emailSend',
      'n8n-nodes-base.dateTime',
      'n8n-nodes-base.compareDatasets',
      'n8n-nodes-base.itemLists',
      'n8n-nodes-base.sort',
      'n8n-nodes-base.limit',
    ];

    if (coreNodes.includes(nodeData.name)) {
      return 10;
    }

    // 通用高频使用节点
    const highFrequencyNodes = [
      'n8n-nodes-base.googleSheets',
      'n8n-nodes-base.mySql',
      'n8n-nodes-base.postgres',
      'n8n-nodes-base.mongoDb',
      'n8n-nodes-base.redis',
      'n8n-nodes-base.webhook',
      'n8n-nodes-base.wait',
      'n8n-nodes-base.splitInBatches',
      'n8n-nodes-base.loopOverItems',
      'n8n-nodes-base.rssFeedRead',
      'n8n-nodes-base.xml',
      'n8n-nodes-base.json',
      'n8n-nodes-base.csv',
      'n8n-nodes-base.htmlExtract',
    ];

    if (highFrequencyNodes.includes(nodeData.name)) {
      return 9;
    }

    // 根据类别评分
    const categoryScores: Record<string, number> = {
      core: 8,
      input: 7,
      output: 7,
      transform: 6,
      cloud: 6,
      communication: 6,
      development: 5,
      files: 5,
      other: 4,
    };

    if (nodeData.category && categoryScores[nodeData.category] !== undefined) {
      return categoryScores[nodeData.category]!;
    }

    // 根据名称关键词评分
    const name = nodeData.name.toLowerCase();

    if (name.includes('http') || name.includes('api') || name.includes('webhook')) {
      return 8;
    }

    if (name.includes('database') || name.includes('sql') || name.includes('db')) {
      return 7;
    }

    if (name.includes('email') || name.includes('slack') || name.includes('discord')) {
      return 6;
    }

    if (name.includes('trigger') || name.includes('schedule')) {
      return 6;
    }

    if (name.includes('aws') || name.includes('google') || name.includes('microsoft')) {
      return 5;
    }

    // 默认推荐值
    return 5;
  }

  /**
   * 关闭数据库连接
   */
  async disconnect(): Promise<void> {
    await this.prisma.$disconnect();
  }
}

// 导出单例实例
export const n8nNodeDb = new N8nNodeDatabaseService();
